/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Recommender.LSH;

import DataModel.ArrDataModel;
import DataModel.MaTrixUser_Item;
import IO.ReadFile;
import java.io.IOException;
import java.util.Random;

/**
 *
 * @author tuyetphuong
 */
public class LSH {

    public int numofhash;
    public int numofkeyhash;
    public Hash[] arrhashfunction;
    MaTrixUser_Item matrix;
   // ArrDataModel arr;
    int[][] HashValue;
    float[][] arrsim;
    float[] Danhgiatrungbinh;
    int[] KLangGieng;
    public void  Init_LSH(ArrDataModel arr) throws IOException
    {
        //ReadFile r = new ReadFile();
        //arr=r.ReadTrainFile("pp");
         numofhash = 100;
        numofkeyhash = 30;
        arr.GetNumOFItem();
        arr.GetNumOFUser();
        matrix = arr.CreateMatrixUser_Item();
        int[] Item = arr.GetItemSet();
        HashValue = ArrHash(Item, matrix, arr);
        arrsim = ArrSim(HashValue, arr);
        Danhgiatrungbinh = DanhGiaTrungBinh(arr);
    }
    public float GetPointLSH(int u , int s, ArrDataModel arr) throws IOException
    {

        KLangGieng = TimKLangGieng(u,0, arrsim, arr);
        float p=PredictPoint(u, s, arr);
        return p;
    }


    public int[] Permute(int[] Item) {
        int[] Item1 = new int[Item.length];
        for (int i = 1; i <= Item.length - 1; i++) {
            Item1[i] = Item[i];
        }
        for (int i = 1; i <= 10000; i++) {
            Random k1 = new Random();
            Random k2 = new Random();
            int a = k1.nextInt(Math.abs(Item.length));
            int b = k2.nextInt(Item.length);
            int temp = Item[a];
            Item1[a] = Item1[b];
            Item1[b] = temp;
        }
        return Item1;
    }

    public int FirstIndex(int[] Item1, int[] Item2) {
        for (int i = 1; i < Item1.length - 1; i++) {
            for (int j = 0; j < Item2.length - 1; j++) {
                if (Item1[i] == Item2[j]) {
                    return i;
                }
            }
        }
        return 0;
    }

    public void CreateHashFunction(int[] Item) {
        arrhashfunction = new Hash[numofhash];
        for (int i = 0; i < numofhash; i++) {
            int[] Item1 = Permute(Item);
            arrhashfunction[i] = new Hash(numofkeyhash, Item1);
        }
    }

    public int[] HashValue(int user, int[] Item, MaTrixUser_Item matrix) {

        arrhashfunction = new Hash[numofhash];
        int[] value = new int[numofhash];
        for (int i = 0; i < numofhash; i++) {
            int[] Item1 = Permute(Item);
            Item = Item1;
            arrhashfunction[i] = new Hash(numofkeyhash, Item1);
            value[i] = FirstIndex(Item1, matrix.arr_user_item[user].ITem);
        }
       return value;
    }

    public int[][] ArrHash(int[] Item, MaTrixUser_Item matrix, ArrDataModel arr) {
        int[][] arrHash = new int[1000+ 1][Item.length];
        for (int i = 0; i < numofhash; i++) {
            int[] Item1 = Permute(Item);
            for (int j = 1; j <= arr._MaxUser; j++) {
                arrHash[j][i] = FirstIndex(Item1, matrix.arr_user_item[j].ITem);
            }
        }

        return arrHash;
    }

    public float Similarity(int user1, int user2, int[] Item, int[][] arrhash) {

        int[] value1 = arrhash[user1];
        int[] value2 = arrhash[user2];
        int count = 0;
        if (user1 != user2) {
            for (int i = 0; i < numofhash; i++) {
                if ((value1[i] == value2[i]) && (value1[i] != 0)) {
                    count++;
                }
            }
        }
        return (float) (1.0 * count / numofhash);

    }

    public float[][] ArrSimilarity(int[] ITem, MaTrixUser_Item matrix, ArrDataModel arr, int[][] arrhash) {
        ITem = arr.GetItemSet();
        arrhash = ArrHash(ITem, matrix, arr);
        float[][] S = new float[1000+ 1][1000 + 1];
        for (int i = 1; i <= arr._MaxUser; i++) {
            for (int j = 1; j <= arr._MaxUser; j++) {
                S[i][j] = 0;
            }
        }
        for (int i = 1; i <= arr._MaxUser - 1; i++) {
            for (int j = i + 1; j <= arr._MaxUser; j++) {
                S[i][j] = Similarity(i, j, ITem, arrhash);
                S[j][i] = S[i][j];
            }
        }

        return S;
    }

    public float sim(int u1, int u2, ArrDataModel arr) {
        int count1 = 0;
        int count2 = 0;
        int[] ITem1 = arr.UserRating(u1);
        int[] ITem2 = arr.UserRating(u2);
        for (int i = 0; i < ITem1.length; i++) {
            for (int j = 0; j < ITem2.length; j++) {
                if (ITem1[i] == ITem2[j]) {
                    count1++;
                }
            }
        }
        count2 = ITem1.length + ITem1.length;
        count2 = count2 - count1;
        float sim = (float) (1.0 * count1 / count2);
        return sim;
    }

    public float[][] ArrSim1(ArrDataModel arr) {
        float[][] Arrsim = new float[1000 + 1][1000 + 1];
        for (int i = 1; i < arr._MaxUser; i++) {
            for (int j = i + 1; j <= arr._MaxUser; j++) {
                Arrsim[i][j] = sim(i, j, arr);
                Arrsim[j][i] = Arrsim[i][j];
            }
        }
        return Arrsim;
    }

    public float[][] ArrSim(int[][] ArrHashValue, ArrDataModel arrmodel) {
        float[][] arrsim = new float[1000+1][1000+1];
        for (int k = 1; k <=1000 ; k++) {
            arrsim[k][k] = 0;
        }
        for (int i = 1; i < arrmodel._MaxUser; i++) {
            for (int j = i + 1; j <= arrmodel._MaxUser; j++) {
                float sim = 0;
                for (int m = 0; m < numofhash; m++) {
                    if (ArrHashValue[i][m] == ArrHashValue[j][m] && (ArrHashValue[i][m] != 0)) {
                        sim++;
                    }
                }
                arrsim[i][j] = (float) (1.0 * sim / numofhash);
                arrsim[j][i] = arrsim[i][j];
            }
        }
        return arrsim;
    }
    public int[] TimKLangGieng(int user, int SoLangGieng, float[][] ArrSim, ArrDataModel arrmodel) {
        SoLangGieng = 0;
        int[] arrLangGieng = new int[4000];
        for (int i = 1; i <= arrmodel._MaxUser; i++) {
            if (ArrSim[user][i] > 0.01) {
                arrLangGieng[SoLangGieng] = i;
                SoLangGieng++;

            }
        }
        int[] arrLangGieng2 = new int[SoLangGieng];
        for (int j = 0; j < SoLangGieng; j++) {
            arrLangGieng2[j] = arrLangGieng[j];

        }
        return arrLangGieng2;
    }

    public float[] DanhGiaTrungBinh(ArrDataModel arr) {
        int[] Count = new int[1000 + 1];
        float[] diemtrungbinh = new float[1000+ 1];
        for (int i = 0; i <= 1000; i++) {
            Count[i] = 0;
        }
        for (int i = 0; i < arr.numofrow; i++) {
            Count[arr.arrmodel.get(i).GetIDUser()]++;
        }
        for (int i = 1; i <= arr._MaxUser; i++) {
            diemtrungbinh[i] = (float) (1.0 * Count[i] / (1.0 * arr._NumOfItem));
        }
        return diemtrungbinh;

    }

    public float PredictPoint(int u, int s, ArrDataModel arr) {
        float rus = 0;
        float rustrungbinh = Danhgiatrungbinh[u];
        float tu = 0;
        float mau = 0;
        for (int i = 0; i < KLangGieng.length; i++) {

            int uphay = KLangGieng[i];
            float rusphaytrungbinh = Danhgiatrungbinh[uphay];
            int danhgiacuanguoidunguphay = 0;
            // danhgiacuanguoidunguphay= matrix.arr_user_item[i].user;
            for (int j = 0; j < arr.numofrow; j++) {
                if (arr.arrmodel.get(j).GetIDItem() == s && arr.arrmodel.get(j).GetIDUser() == uphay) {
                    danhgiacuanguoidunguphay = arr.arrmodel.get(i).GetRating();
                }
            }
            tu = tu + (Math.abs(danhgiacuanguoidunguphay - Danhgiatrungbinh[uphay]) * arrsim[u][uphay]);
            mau += arrsim[u][uphay];

        }
        if(mau!=0)
        {
         rus = Danhgiatrungbinh[u] + (float) ((1.0 * tu) / (1.0 * mau));
        }
        return rus;
    }

    public int GetPoint_LSH_Standar(int u, int s, ArrDataModel arr) {
        if (PredictPoint(u, s, arr) > 0.3) {
            return 1;
        } else {
            return 0;
        }
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IOException {
        // TODO code application logic here

        LSH lsh = new LSH();

        ReadFile r = new ReadFile();
        ArrDataModel arr= new ArrDataModel();
        arr= r.ReadTrainFile("pp");
         lsh.Init_LSH(arr);
        int u =1;
        int s=1;

        System.out.print(lsh.GetPointLSH(u, s, arr));
        System.out.print("\n");
      /*  float f;
        int sotuvandung = 0;
        int sotuvan = 0;
        int sodanhgia = 0;
        int sodanhgiadung = 0;
        int taptest = 0;
        float recall = 0;
        float precsion = 0;
        float mae = 0;
        float rmse = 0;
        int solantuvanrecall = 0;
        int solantuvanprecsion = 0;
        ReadFile readfile = new ReadFile();
        ArrDataModel arr1 = new ArrDataModel();
        arr1 = readfile.TestFile20();
        ArrDataModel arr = new ArrDataModel();
        arr= readfile.ReadTrainFile("pp");
        arr1.GetNumOFItem();
        arr1.GetNumOFUser();
        LSH lsh = new LSH();
        taptest = arr1.numofrow;
        for (int i = 0; i < arr1.numofrow; i++) {
            //lsh.KLangGieng = lsh.TimKLangGieng(arr1.arrmodel[i].GetIDUser(), 0, lsh.arrsim, lsh.arr);
           if (lsh.GetPointLSH(arr1.arrmodel[i].GetIDUser(), arr1.arrmodel[i].GetIDItem(), arr) == 1) {
                sodanhgiadung++;
            }
        }/*
        float p = (float) 0.0;
        p = (taptest - sodanhgiadung);
        p = p / taptest;
        mae = p;
        System.out.print(mae);
        System.out.print("\n");
        p = (float) Math.sqrt(p);
        rmse = p;
        System.out.print(rmse);
        System.out.print("\n");
        p = (float) Math.sqrt(p);
        int[] itemset = arr1.GetItemSet();
        int[] userset = arr1.GetUserSet();
        for (int i = 0; i < userset.length; i++) {
            int[] taptuvan = new int[1000];
            sotuvan = 0;
            int[] ratingset = arr1.UserRating(userset[i]);
            for (int j = 0; j < itemset.length; j++) {
                if (lsh.DuDoanDiem(userset[i], itemset[j]) >= 0.6) {
                    taptuvan[sotuvan] = itemset[j];
                    sotuvan++;
                }
            }
            sotuvandung = 0;
            for (int ii = 0; ii < ratingset.length; ii++) {
                for (int j = 0; j < sotuvan; j++) {
                    if (ratingset[ii] == taptuvan[j]) {
                        sotuvandung++;
                    }
                }
            }
            if (ratingset.length != 0) {
                recall += (float) sotuvandung / (float) ratingset.length;
                solantuvanrecall++;
            }
            if (sotuvan != 0) {
                precsion += (float) sotuvandung / (float) sotuvan;
                solantuvanprecsion++;
            }
        }
        recall = (float) recall / (float) solantuvanrecall;
        System.out.print(recall);
        System.out.print("\n");
        precsion = (float) precsion / (float) solantuvanprecsion;
        System.out.print(precsion);
        System.out.print("\n");
        f = 2 * recall * precsion / (recall + precsion);
        System.out.print(f);
        System.out.print("\n");*/

    }
}
